﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Bioinformatics.Algorithms;
using System.Threading;
using Bioinformatics.Types;

namespace Bioinformatics.Algorithms
{
    public class PsomlParallelFx : PsomlNative
    {
        public PsomlParallelFx()
        {
            AlgorithmName = "PSOML Parallel Extensions .NET";
        }

        public override void AutoRun()
        {
            //initialize swarm
            for (var i = 0; i < Swarm.Length; i++)
                Swarm[i] = new Particle(Phylogeny, LengthMax, LengthMin, LengthDeltaMax, LengthDeltaMin, Swarm.Length, NeighborhoodSize);

            for (var i = 0; i < GenerationMax; i++)
            {
                //calculate likelihood for all particles in swarm
                Parallel.For(0, Swarm.Length, s => Swarm[s].CalculateLikelihood());
                //sort the array by likelihood - find global best
                Array.Sort(Swarm, Particle.Comparer);
                Particle.BranchLengthGlobalBest = (float[])Swarm[0].BranchLengths.Clone();
                //Array.Copy(Swarm[0].BranchLengths, Particle.BranchLengthGlobalBest, Swarm[0].BranchLengths.Length);
                //update local best
                Parallel.For(0, Swarm.Length, s =>
                                                  {
                                                      var nMax = 0;
                                                      for (var n = 0; n < Swarm[s].Neighbourhood.Length; n++)
                                                          if (Swarm[n].Likelihood > Swarm[nMax].Likelihood)
                                                              nMax = n;
                                                      Swarm[s].BranchLengthsNeighbourhoodBest =
                                                          (float[]) Swarm[nMax].BranchLengths.Clone();
                                                  });
                //adjust the velocities of each particle
                Parallel.For(0, Swarm.Length, s => Swarm[s].AdjustVelocities());
                //update the position of each particle in the swarm
                Parallel.For(0, Swarm.Length, s => Swarm[s].UpdateBranchLengths());
            }
        }
    }
}